/**
 * @(#)Manager.java		1.0		17/04/2012
 */
package upm.pb4agent.team8;

import java.security.acl.Acl;

import upm.pb4agent.common.Constant;
import upm.pb4agent.ontology.AssignBoat;
import upm.pb4agent.ontology.Boat;
import upm.pb4agent.ontology.Dock;
import upm.pb4agent.ontology.EnteringDock;
import upm.pb4agent.ontology.Owns;
import upm.pb4agent.ontology.PB4AgentOntology;
import upm.pb4agent.ontology.PickSeat;
import upm.pb4agent.ontology.RaceFinished;
import upm.pb4agent.ontology.RaceStarted;
import upm.pb4agent.ontology.Row;
import upm.pb4agent.ontology.Seat;
import upm.pb4agent.team8.Common.PB4Utils;
import upm.pb4agent.team8.Common.SubscribeAgentBehaviour;
import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.Predicate;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.SimpleBehaviour;
import jade.domain.introspection.AddedBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

public class Rower extends Agent
{
	private static final long serialVersionUID = 8653245752537015358L;
	private Codec codec = new SLCodec();
	private Ontology ontology = PB4AgentOntology.getInstance();
	
	protected Boat _boat;
	private int _currentSeat =-1;
	private AID _watcherAID = null;
	private boolean _isRaceOngoing = false;
	private Dock _dock; //The manager defines the dock position
	private int _defaultInitialSeat = 5;  // This because the strategy used.

	protected void setup()
	{
		PB4Utils.Console.WriteLine(getLocalName() + ": Enters the system");
		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);

		PB4Utils.TryRegisterAgent(this,this.getLocalName());
		
		Object[] args = getArguments();
		if (args != null) {
			_dock = (Dock) args[0];
		}
		
		addBehaviour(new HandleRaceEventMessagesBehavior(this));
		addBehaviour(new SubscribeAgentBehaviour(this));
		addBehaviour(new AssignedBoatBehavior(this));
		addBehaviour(new StartRowingBehaviour(this));
	}
	
	class AssignedBoatBehavior extends SimpleBehaviour
	{
		Rower _agent;
		public AssignedBoatBehavior(Agent agent)
		{
			super(agent);
			_agent=(Rower)agent;
		}
		
		private boolean _finished = false;
		@Override
		public void action() 
		{
	        ACLMessage msg = receive(MessageTemplate.MatchProtocol(PB4AgentOntology.ASSIGNBOAT));
	        if (msg != null) 
	        { 
		    	ContentElement content = PB4Utils.GetMessageContent(_agent, msg);
		        switch (msg.getPerformative()) 
		        {			        			
		         	case (ACLMessage.INFORM):
		         		Concept msgAction = ((Action)content).getAction();
						if ( msgAction instanceof AssignBoat)
						{
							AssignBoat boat = (AssignBoat)msgAction;		
							_boat= boat.getBoat();
							//Only the one corresponding to First dock sends the message.
							if ( _dock.getName().equals(Constant.DockNumber.A.toString()))
							{
								NotifyInitialBoatSeatSelection(boat.getBoat().getID());
								_finished = true;
							}
						}
						break;
		         }
	        }
		    else
	        {
	        	block();
	        }
		}
		
		private void NotifyInitialBoatSeatSelection( AID boatID)
		{
			_currentSeat = _defaultInitialSeat;
			String selectedSeat = Integer.toString(_currentSeat);
			PB4Utils.Console.WriteLine(getLocalName() + " picked Seat " + selectedSeat );
			Seat seat= new Seat();
			seat.setSeatID(selectedSeat);
			PickSeat pickSeat= new PickSeat();
			pickSeat.setSeatID(seat);
			
			PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, boatID, pickSeat);
		}
		
		@Override
		public boolean done()
		{
			return _finished;
		}
	}
	
	class HandleRaceEventMessagesBehavior extends SimpleBehaviour
	{
		private boolean _finished =false;
		Rower _agent;
		
		public HandleRaceEventMessagesBehavior(Rower agent)
		{
			_agent = agent;
		}
		
		@Override
		public void action() 
		{				        
			ACLMessage msg = receive(MessageTemplate.or(
					 MessageTemplate.or(
					 MessageTemplate.or(
					 MessageTemplate.MatchProtocol(PB4AgentOntology.RACESTARTED),
					 MessageTemplate.MatchProtocol(PB4AgentOntology.ENTERINGDOCK)),
					 MessageTemplate.MatchProtocol(PB4AgentOntology.LEAVINGDOCK)),
					 MessageTemplate.MatchProtocol(PB4AgentOntology.RACEFINISHED)));
			
	        if (msg == null)
	        {return; }
	        
	        ContentElement content = PB4Utils.GetMessageContent(_agent, msg);
	        switch (msg.getPerformative()) 
	        {
	         	case (ACLMessage.INFORM):
	         		Concept msgAction = ((Action)content).getAction();
					if ( msgAction instanceof RaceStarted)
					{
						_watcherAID = PB4Utils.TryFindAgent(_agent, Constant.WATCHER);
						if (_dock.getName().equals("A"))
						{
							_isRaceOngoing = true;							
							System.out.println(getLocalName() + ": Race Started message received");
						}
					}
					else if ( msgAction instanceof EnteringDock)
					{
						EnteringDock newDock =(EnteringDock)msgAction;
						SetupSeats( newDock );
					}
					else if ( msgAction instanceof RaceFinished)
					{
						_isRaceOngoing = false;
						_finished = true;
						System.out.println(getLocalName() + ": Race Finished message received");
					}	
	         }
		}
		
		private void SetupSeats(EnteringDock enterDock)
		{
			Dock newDock = enterDock.getDock();
			if ( newDock.getName().equals("B"))
			{
				if (_dock.getName().equals("B"))
				{
					_currentSeat = 2;
					NotifyInitialBoatSeatSelection(_boat.getID(), 2);
					_isRaceOngoing = true;
				}
			}
			else if ( newDock.getName().equals("C"))
			{
				if (_dock.getName().equals("A"))
				{
					_currentSeat = 4;
					NotifyInitialBoatSeatSelection(_boat.getID(), 4);
				}
				if (_dock.getName().equals("B"))
				{
					_currentSeat = 6;
					NotifyInitialBoatSeatSelection(_boat.getID(), 6);
				}
				if (_dock.getName().equals("C"))
				{
					_currentSeat = 2;
					NotifyInitialBoatSeatSelection(_boat.getID(), 2);
					_isRaceOngoing = true;
				}
			}
			else if ( newDock.getName().equals("D"))
			{
				if (_dock.getName().equals("C"))
				{
					_currentSeat = 1;
					NotifyInitialBoatSeatSelection(_boat.getID(), 1);
				}
				if (_dock.getName().equals("D"))
				{
					_currentSeat = 3;
					NotifyInitialBoatSeatSelection(_boat.getID(), 3);
					_isRaceOngoing = true;
				}				
			}			
		}
		
		private void NotifyInitialBoatSeatSelection( AID boatID, int newSeat)
		{
			String selectedSeat = Integer.toString(newSeat);
			PB4Utils.Console.WriteLine(getLocalName() + " picked Seat " + selectedSeat );
			Seat seat= new Seat();
			seat.setSeatID(selectedSeat);
			PickSeat pickSeat= new PickSeat();
			pickSeat.setSeatID(seat);
			
			PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, boatID, pickSeat);
		}
		
		@Override
		public boolean done()
		{
			return _finished;
		}

	}

	class StartRowingBehaviour extends CyclicBehaviour
	{
		Rower _agent;
		public StartRowingBehaviour(Rower agent)
		{
			_agent = agent;
		}
		
		@Override
		public void action() 
		{
			StartRowing();
		}
		
		private void StartRowing()
		{
			if ( _isRaceOngoing == false )
				return;
			
			switch (_currentSeat) {
			case 1:
				PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, _watcherAID, GetRowingInformation(1));
				break;
			case 4:
				PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, _watcherAID, GetRowingInformation(2));
				break;
			case 2:
				PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, _watcherAID, GetRowingInformation(1));
				PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, _watcherAID, GetRowingInformation(2));
				break;
			case 5:
				PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, _watcherAID, GetRowingInformation(3));
				PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, _watcherAID, GetRowingInformation(4));
				break;
			case 3:
				PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, _watcherAID, GetRowingInformation(2));
				break;
			case 6:
				PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, _agent, _watcherAID, GetRowingInformation(4));
				break;
			default:
				break;
			}
			
			try {
				Thread.sleep(200L);
			} catch (Exception e) {}
		}
		
		private Row GetRowingInformation(int oar)
		{
			Row row = new Row();
			row.setDirection(Constant.Direction.Forward.ordinal());
			row.setStrength(Constant.Impulse.Strong.ordinal());
			row.setOarID(Integer.toString(oar));
			row.setBoat(_boat);
			return row;
		}		
	} 

}
